home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / mfs6011s.zoo / fsck / fsck.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-31  |  32.9 KB  |  1,605 lines

  1. /* Filesystem checker : Contains most of the elements of BSD fsck(8) that
  2.  * make sense under minix filesystems.
  3.  * Copyright 1992,1993,1994 S.N. Henson, all rights reserved.
  4.  * Version 0.1 
  5.  */
  6.  
  7.  
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <alloc.h>
  11. #include <time.h>
  12. #include <stdio.h>
  13. #include <macros.h>        /* For min(x,y) */
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <time.h>
  17.  
  18. #include "fs.h"
  19. #include "fsck.h"
  20. #include "global.h"
  21. #include "proto.h"
  22. #include "stproto.h"
  23.  
  24. void do_fsck()
  25. {
  26.     int pass;
  27.     long i;
  28.     llist *tll;
  29.     
  30.     /* Filesystem dependent check */
  31.  
  32.     i = 2+Super->s_zmap_blks+Super->s_imap_blks
  33.                         +(Super->s_ninodes+IPB-1)/IPB;
  34.  
  35.     if( Super->s_firstdatazn < i ) sfatal("First Data Zone too small");
  36.  
  37.     /* Maybe using new protection ? */
  38.     if( Super->s_firstdatazn > i ) 
  39.     {
  40.         unsigned char *tblock;
  41.         long secsize;
  42.         tblock = malloc(BLOCKSIZE);
  43.         if(!tblock) fatal("No memory for boot sector buffer");
  44.         read_zone(0,tblock);
  45.         secsize = tblock[0xb]+(tblock[0xc]<<8);
  46.         if( ((secsize & 1023 ) == 0))
  47.         {
  48.             secsize/=1024;
  49.             i+= 2 * secsize - 1;
  50.             i/=secsize;
  51.             i*=secsize;
  52.         }
  53.         free(tblock);
  54.     }
  55.  
  56.     if( Super->s_firstdatazn != i ) fprintf(stderr,"Warning: First data" 
  57.         " zone block %d, expected %ld\n",Super->s_firstdatazn,i);
  58.  
  59.     /* Allocate status arrays */
  60.  
  61.     ibitmap=calloc(BLOCKSIZE*(Super->s_zmap_blks*2 + Super->s_imap_blks) +
  62.                     sizeof(inode_stat)*Super->s_ninodes,1);
  63.  
  64.     if(!ibitmap)fatal("No memory for Zone bitmaps");
  65.  
  66.     zbitmap=(unsigned *)( ( (long)ibitmap )+ BLOCKSIZE*Super->s_imap_blks);
  67.     szbitmap=(unsigned *)( ( (long)zbitmap ) + BLOCKSIZE*Super->s_zmap_blks);
  68.     inode_status=(inode_stat *)(szbitmap +(szbitmap-zbitmap));
  69.  
  70.     setbit(0,szbitmap);
  71.  
  72.     /* Flags for root inode */
  73.     inode_status->flag |= I_FOUND;
  74.     inode_status->parent= ROOT_INODE;
  75.  
  76.     /* Read in all bitmaps */
  77.     read_blocks(2,Super->s_imap_blks+Super->s_zmap_blks,ibitmap);
  78.     ioff=2+Super->s_imap_blks+Super->s_zmap_blks;
  79.  
  80.     for (tll = zinums; tll; tll = tll->next) {
  81.       if ( (tll->member > ROOT_INODE) && (tll->member <= maxino)) 
  82.                 inode_status[tll->member-1].flag |= I_ZAP;
  83.       else fprintf (stderr, "Invalid inode number %ld\n", tll->member);
  84.     }
  85.  
  86.     check_root();
  87.  
  88.     printf("Pass 1 Checking All Inodes\n");
  89.  
  90.     ist=inode_status;
  91.     next_init();
  92.  
  93.     for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  94.     {
  95.         next_inode();
  96.         if(badroot && (cino==ROOT_INODE) ) continue;
  97.         if (ist->flag & I_ZAP) {
  98.           *rip=zinode;
  99.           ist->flag |=I_FREE;
  100.           cdirty = 1;
  101.           continue;
  102.         }
  103.         ist->links = rip->i_nlinks;
  104.         switch(rip->i_mode & I_TYPE)
  105.         {
  106.             case I_NOT_ALLOC:
  107.             ist->flag|=I_FREE;
  108.             if(rip->i_nlinks)
  109.             {
  110.                 printf("Non zero link count for Free inode %ld\n",cino);
  111.                 if(ask("Alter?","Altered"))
  112.                 {
  113.                     rip->i_nlinks=0;
  114.                     ist->links=0;
  115.                     cdirty=1;
  116.                 }
  117.             }
  118.             break;
  119.  
  120.             case I_CHAR_SPECIAL:
  121.             nchr++;
  122.             break;
  123.  
  124.             case I_BLOCK_SPECIAL:
  125.             nblk++;
  126.             break;
  127.  
  128.             case I_NAMED_PIPE:
  129.             nfifo++;
  130.             break;
  131.  
  132.             case I_REGULAR:
  133.             nreg++;
  134.             traverse_zones(pass1);
  135.             break;
  136.  
  137.             case I_DIRECTORY:
  138.             if(rip->i_size & (DSIZE*incr-1))
  139.             {
  140.                 inerr("Partial Entry");
  141.                 if(ask("Truncate?","Truncated"))
  142.                 {
  143.                     rip->i_size &= ~(DSIZE*incr-1);
  144.                     cdirty=1;
  145.                     trunc=2;
  146.                 }
  147.             }
  148.             traverse_zones(pass1);
  149.             if (dirsparse) {
  150.                 inerr("Sparse directory");
  151.                 if(ask("Make regular?","Changed"))
  152.                 {
  153.                     rip->i_mode &= ~I_TYPE;
  154.                     rip->i_mode |= I_REGULAR;
  155.                     cdirty=1;
  156.                     nreg++;
  157.                     break;
  158.                 }
  159.             }
  160.             ndir++;
  161.             trunc=0;
  162.             ist->flag|=I_DIR;
  163.             break;
  164.  
  165.             case I_OLDLINK:
  166.             inerr("Old style symbolic link");
  167.             if(ask("Convert?","Converted"))
  168.             {
  169.                 rip->i_mode &= ALL_MODES;
  170.                 rip->i_mode |= I_SYMLINK;
  171.                 cdirty=1;
  172.             }
  173.             /* Fall through */
  174.  
  175.             case I_SYMLINK:
  176.             nsym++;
  177.             traverse_zones(pass1);
  178.             break;
  179.  
  180.             default:
  181.             printf("Unknown Mode 0%o Inode %ld\n",rip->i_mode,cino);
  182.             if(ask("Clear?","Cleared"))
  183.             {
  184.                 *rip=zinode;
  185.                 cdirty=1;
  186.                 ist->links=0;
  187.             }
  188.         }
  189.     }
  190.  
  191.     if(fzlist)
  192.     {
  193.         if(preen) fatal("Duplicate zones found when preening");
  194.         printf("Pass 1a finding duplicate zones\n");
  195.         next_init();
  196.         for(cino=ROOT_INODE;cino<=maxino;cino++)
  197.         {
  198.             next_inode();
  199.             if(badroot && (cino==ROOT_INODE) ) continue; 
  200.             switch(rip->i_mode & I_TYPE)
  201.             {
  202.                 case I_SYMLINK:
  203.                 case I_REGULAR:
  204.                 case I_DIRECTORY:
  205.                 traverse_zones(pass1a);
  206.  
  207.                 default:
  208.                 break;
  209.             }
  210.         }
  211.     }
  212.  
  213.     next_init();
  214.  
  215.     if(badroot) fix_root();
  216.  
  217.     for(pass=0;pass<4;pass++)
  218.     {
  219.         char first=0;
  220.         switch(pass)
  221.         {
  222.             case 0:
  223.             printf("Pass 2 Reading Directories\n");
  224.             break;
  225.             
  226.             case 1:
  227.             printf("Pass 3 Checking Connectivity\n");
  228.             break;
  229.  
  230.             case 2:
  231.             case 3:
  232.             first=0;
  233.             break;
  234.         }
  235.         read_inode_init();
  236.         ist=inode_status;
  237.         for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  238.         {
  239.             if(!(ist->flag & I_DIR)) continue;
  240.             if( (pass==2) && !(ist->flag & I_LINK) ) continue;
  241.             if( (pass==3) && ( !(ist->flag & (I_FDD|I_FIXDD)) 
  242.                     || !(ist->flag & I_DD) ) ) continue;
  243.             read_inode();
  244.             switch(pass)
  245.             {
  246.                 case 0:
  247.                 check_dots();
  248.                 break;
  249.  
  250.                 case 1:
  251.                 traverse_dir(pass2);
  252.                 break;
  253.  
  254.                 case 2:
  255.                 if(!first)
  256.                 {
  257.                     printf("Pass 3a Fixing Directories\n");
  258.                     first=1;
  259.                 }
  260.                 traverse_dir(pass2a);
  261.                 break;
  262.  
  263.                 case 3:
  264.                 if(!first)
  265.                 {
  266.                     printf("Pass 3b Fixing Dots\n");
  267.                     first=1;
  268.                 }
  269.                 fix_dots();
  270.                 break;
  271.             }
  272.         }
  273.     }
  274.     ist=inode_status;
  275.  
  276.     if(inolist)
  277.     {
  278.         ilist *p;
  279.         for(p=inolist;p;p=p->next) show_name(p);
  280.     }
  281.  
  282.     for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  283.     {
  284.  
  285.         if( !(ist->flag & I_FOUND) && !(ist->flag & I_FREE) )
  286.         {
  287.             inerr("Orphaned Inode");
  288.             if(ask("Reconnect?","Reconnected"))
  289.             {
  290.                 dir_struct tdir[DPB/2];
  291.                 unsigned tino;
  292.                 if(lfinode || mklost() )
  293.                 {
  294.                 read_inode();
  295.                 cdirty=1;
  296.                 tino=cino;
  297.                 rip->i_nlinks++;
  298.  
  299.                 /* Fix link count as well */
  300.                 rip->i_nlinks-=ist->links;
  301.                 ist->links=0;
  302.  
  303.                 /* Update '..' */
  304.                 if(ist->flag & I_DD)
  305.                 {
  306.                     dir_struct dir[DPB];
  307.                     read_zone(rip->i_zone[0],dir);
  308.                     dir[incr].d_inum=lfinode;
  309.                     write_zone(rip->i_zone[0],dir);
  310.  
  311.                     if(chk_irange(ist->parent))
  312.                     {    
  313.                     inode_status[ist->parent-1].links++;
  314.                     cino=ist->parent;
  315.                     read_inode();
  316.                     cdirty=1;
  317.                     rip->i_nlinks--;
  318.                     }
  319.  
  320.                 }
  321.  
  322.                 cino=lfinode;
  323.                 sprintf(tdir[0].d_name,"%d",tino);
  324.                 tdir[0].d_inum=tino;
  325.  
  326.                 read_inode();
  327.                 if(ist->flag & I_DD) rip->i_nlinks++;
  328.                 cdirty=1;
  329.                 add_dirent(tdir);
  330.                 cino=tino;
  331.                 }
  332.             else printf("Cannot Reconnect\n");
  333.             }    
  334.         }
  335.  
  336.         if(ist->links)
  337.         {
  338.             printf("Inode %ld Bad Link Count\n",cino);
  339.             if(ask("Alter?","Altered"))
  340.             {
  341.                 read_inode();
  342.                 rip->i_nlinks-=ist->links;
  343.                 ist->links=0;
  344.                 cdirty=1;
  345.             }
  346.         }
  347.  
  348.     }
  349.  
  350.     read_inode_init();
  351.  
  352.     printf("Checking Zone Bitmap\n");
  353.     for(i=1;i<=maxzone-minzone+1;i++)
  354.     {
  355.         if(!isset(i,szbitmap))
  356.         {
  357.             zfree++;
  358.             if(isset(i,zbitmap)) berr++;
  359.         }
  360.         else if(!isset(i,zbitmap)) berr++;
  361.     }
  362.  
  363.     if(berr)
  364.     {
  365.         printf("Zone Bitmap : %ld Errors\n",berr);
  366.         if(ask("Install A New Map?","Fixed"))
  367.         {
  368.             int maxbit = Super->s_zmap_blks * BLOCKSIZE * 8;
  369.             for(i=1;i<=maxzone-minzone+1;i++)
  370.             {
  371.                 if(isset(i,szbitmap)) setbit(i,zbitmap);
  372.                 else clrbit(i,zbitmap);
  373.             }
  374.             for (; i < maxbit; i++)
  375.               setbit (i, zbitmap);
  376.             write_blocks(2+Super->s_imap_blks,Super->s_zmap_blks,zbitmap);
  377.         }
  378.     }
  379.     else printf("Zone Bitmap OK\n");
  380.  
  381.     berr=0;
  382.     ist=inode_status;
  383.     printf("Checking Inode Bitmap\n");
  384.  
  385.     for(i=ROOT_INODE;i<=maxino;i++,ist++)
  386.     {
  387.         if( ist->flag & I_FREE)
  388.         {
  389.             ifree++;
  390.             if(isset(i,ibitmap)) berr++;
  391.         }
  392.         else if(!isset(i,ibitmap)) berr++;
  393.     }
  394.  
  395.     if(berr)
  396.     {
  397.         printf("Inode Bitmap : %ld Errors\n",berr);
  398.         if(ask("Install A New Map?","Fixed"))
  399.         {
  400.             int maxbit = Super->s_imap_blks * BLOCKSIZE * 8;
  401.             ist=inode_status;
  402.             for(i=ROOT_INODE;i<=maxino;i++,ist++)
  403.             {
  404.                 if(ist->flag & I_FREE) clrbit(i,ibitmap);
  405.                 else setbit(i,ibitmap);
  406.             }
  407.             for (; i < maxbit; i++)
  408.               setbit (i, ibitmap);
  409.             write_blocks(2,Super->s_imap_blks,ibitmap);
  410.         }
  411.     }
  412.     else printf("Inode Bitmap OK\n");
  413.  
  414.     read_inode_init();
  415.  
  416. }
  417.  
  418. /* traverse_zones passes pointers of the zone numbers of inode 'rip' to the 
  419.  * function argument, if the value returned is non-zero then number was altered.
  420.  * Also pass a 'level' parameter, this is zero for zone numbers, 1 for 
  421.  * indirection blocks, 2 for double indirection blocks and 3 for
  422.  * triple indirection blocks.
  423.  */
  424.  
  425. static void traverse_zones(func)
  426. int (*func)(zone_nr *zone,unsigned level);
  427. {
  428.     zone_nr i,j;
  429.     zone_nr tmp1[NINDIR],tmp2[NINDIR];
  430.  
  431.     zonecount=(rip->i_size+BLOCKSIZE-1)/BLOCKSIZE;
  432.     indcount=NO_IND(zonecount);
  433.     dindcount=NO_DBL(zonecount);
  434. #ifdef V2
  435.     tindcount = NO_TRPL (zonecount);
  436. #endif
  437.  
  438.     if(trunc!=2) trunc=0; /* 2 means silently truncate (directory) */
  439.     done_trunc=0;
  440.     dirsparse=0;
  441.  
  442.     for(i=0;i<NR_ZONE;i++)
  443.         if( (*func)(&rip->i_zone[i],(i<NDIR) ? 0 : (i-NDIR+1) ) )
  444.                                        cdirty=1;
  445.  
  446.     if( chk_range(rip->i_zone[NDIR]) )
  447.     {
  448.         int zdirty=0;
  449.         read_zone(rip->i_zone[NDIR],tmp1);
  450.  
  451.         for(i=0;i<NINDIR;i++) if( (*func)(&tmp1[i],0) ) zdirty=1;
  452.         if(zdirty) write_zone(rip->i_zone[NDIR],tmp1);
  453.     }
  454.     else zonecount-=NINDIR;
  455.  
  456.     if( chk_range(rip->i_zone[NDIR+1]) )
  457.     {
  458.         int zdirty=0;
  459.         read_zone(rip->i_zone[NDIR+1],tmp1);
  460.         for(i=0;i<NINDIR;i++)
  461.         {
  462.             if( (*func)(&tmp1[i],1) )
  463.             {
  464.                 zdirty=1;
  465.                 continue;
  466.             }
  467.             if( chk_range(tmp1[i]) )
  468.             {
  469.                 int zdirty2=0;
  470.                 read_zone(tmp1[i],tmp2);
  471.                 for(j=0;j<NINDIR;j++)
  472.                     if( (*func)(&tmp2[j],0) ) zdirty2=1;
  473.                 if(zdirty2) write_zone(tmp1[i],tmp2);
  474.             }
  475.             else zonecount-=NINDIR;
  476.  
  477.         }
  478.         if(zdirty) write_zone(rip->i_zone[NDIR+1],tmp1);
  479.     }
  480. #ifdef V2
  481.     else
  482.       zonecount -= (long) NINDIR * NINDIR;
  483.     if (chk_range (rip->i_zone[NDIR + 2]))
  484.       {
  485.         int zdirty = 0;
  486.         read_zone (rip->i_zone[NDIR + 2], tmp1);
  487.         for (i = 0; i < NINDIR; i++)
  488.           {
  489.         if (func (&tmp1[i], 2))
  490.           {
  491.             zdirty = 1;
  492.             continue;
  493.           }
  494.         if  (chk_range (tmp1[i]))
  495.           {
  496.             int zdirty2 = 0;
  497.             read_zone (tmp1[i], tmp2);
  498.             for (j = 0; j < NINDIR; j++)
  499.               {
  500.             if (func (&tmp2[j], 1))
  501.               {
  502.                 zdirty2 = 1;
  503.                 continue;
  504.               }
  505.             if (chk_range (tmp2[j]))
  506.               {
  507.                 int zdirty3 = 0;
  508.                 int k;
  509.                 zone_nr tmp3[NINDIR];
  510.                 read_zone (tmp2[j], tmp3);
  511.                 for (k = 0; k < NINDIR; k++)
  512.                   if (func (&tmp3[k], 0))
  513.                 zdirty3 = 1;
  514.                 if (zdirty3)
  515.                   write_zone (tmp2[j], tmp3);
  516.               }
  517.             else
  518.               zonecount -= NINDIR;
  519.               }
  520.             if (zdirty2)
  521.               write_zone (tmp1[i], tmp2);
  522.           }
  523.         else
  524.           zonecount -= (long) NINDIR * NINDIR;
  525.           }
  526.         if (zdirty)
  527.           write_zone (rip->i_zone[NDIR + 2], tmp1);
  528.       }
  529. #endif
  530. }
  531.  
  532. /* Pass 1 zone traversal , check zone range and note in bitmap, do truncation
  533.  * if too many zones.
  534.  */
  535.  
  536. static int pass1(zone,level)
  537. zone_nr *zone;
  538. unsigned level;
  539. {
  540.  
  541.     if(!done_trunc || trunc)
  542.     {
  543.         switch(level)
  544.         {
  545.             case 0:
  546.  
  547.             if(zonecount==0)
  548.             {
  549.                 if(*zone && ( trunc || do_trunc() ) )
  550.                 {
  551.                     *zone=0;
  552.                     return 1;
  553.                 }
  554.             }
  555.             else {
  556.                 if (!*zone)
  557.                     ++dirsparse;
  558.                 zonecount--;
  559.             }
  560.             break;
  561.  
  562.             case 1:
  563.             if(indcount==0)
  564.             {
  565.                 if(*zone && ( trunc || do_trunc() ) )
  566.                 {
  567.                     *zone=0;
  568.                     return 1;
  569.                 }
  570.             }
  571.             else {
  572.                 if (!*zone)
  573.                     ++dirsparse;
  574.                 indcount--;
  575.             }
  576.             break;
  577.  
  578.             case 2:
  579.             if(dindcount==0)
  580.             {
  581.                 if(*zone && (trunc || do_trunc() ) )
  582.                 {
  583.                     *zone=0;
  584.                     return 1;
  585.                 }
  586.             }
  587.             else {
  588.                 if (!*zone)
  589.                     ++dirsparse;
  590.                 dindcount--;
  591.             }
  592.             break;
  593.  
  594. #ifdef V2
  595.               case 3:
  596.             if (tindcount == 0)
  597.               {
  598.                 if (*zone && (trunc || do_trunc()))
  599.                   {
  600.                 *zone = 0;
  601.                 return 1;
  602.                   }
  603.               }
  604.             else
  605.               tindcount--;
  606.             break;
  607. #endif
  608.         }
  609.     }
  610.  
  611.     if(!*zone) return 0; /* zero is legitimate */
  612.     if( (*zone < minzone) || (*zone > maxzone) )
  613.     {
  614.         printf("Zone number out of range in inode %ld\n",cino);
  615.         if(ask("Remove?","Removed"))
  616.         {
  617.             *zone=0;
  618.             return 1;
  619.         }
  620.     }
  621.     else if(mark_zone(*zone)) add_dup(*zone);
  622.     return 0;
  623. }
  624.  
  625. /* Comment : at the end of pass 1 we have a (possibly empty) list of duplicate
  626.  * zones. The crucial point is that they are in the order of finding by 
  627.  * traverse_zones, except the first element is missing, this is tackled by
  628.  * pass1a.
  629.  */
  630.  
  631. /* Pass 1a zone traversal , find first duplicate zones and fix */
  632.  
  633. static int pass1a(zone,level)
  634. zone_nr *zone;
  635. unsigned level;
  636. {
  637.     if(!chk_range(*zone)) return 0;
  638.     if(is_dup(*zone))
  639.     {
  640.         /* Found first member of duplicate zones, prepend
  641.          * to list.
  642.          */
  643.  
  644.         zlist *new;
  645.         new=malloc(sizeof(zlist));
  646.         if(!new) fatal("No memory for duplist\n");
  647.         new->next=fzlist;
  648.         new->mod=rip->i_mtime;
  649.         new->inum=cino;
  650.         new->zone=*zone;
  651.         new->flag=0;
  652.         fzlist=new;
  653.         do_dup(*zone);
  654.     }
  655.     if(is_rem(*zone))
  656.     {
  657.         printf("Removing Zone %ld Inode %ld\n",(long)*zone,cino);
  658.         *zone=0;
  659.         return 1;
  660.     }
  661.     return 0;
  662. }
  663.  
  664. /* add_dup(zone) adds 'zone' to the duplicate list, this is put at the end
  665.  * so that the duplicate zone reflects the position of finding.
  666.  */
  667.  
  668. static void add_dup(zone)
  669. zone_nr zone;
  670. {
  671.     zlist *tlist;
  672.     tlist=(zlist *)malloc(sizeof(zlist));
  673.     if(!tlist) fatal("No memory for duplicate list");
  674.     tlist->zone=zone;
  675.     tlist->inum=cino;
  676.     tlist->mod=rip->i_mtime;
  677.     tlist->next=NULL;
  678.     tlist->flag=0;
  679.     if(lzlist)
  680.     {
  681.         lzlist->next=tlist;
  682.         lzlist=tlist;
  683.     }
  684.     else
  685.     {
  686.         fzlist=tlist;
  687.         lzlist=tlist;
  688.     }
  689. }
  690.  
  691. /* This determines what happens when duplicate zones are all found, the
  692.  * flag FOUND is set on each zone so that we now know that all the list
  693.  * of duplicates for this zone is complete. The user has the choice to
  694.  * remove each zone. Each removal is noted by the flag REMOVE, so that
  695.  * when the zones are tested by is_rem(), they are removed in order.
  696.  */
  697.  
  698. static void do_dup(zone)
  699. zone_nr zone;
  700. {
  701.     zlist *p;
  702.     printf("Zone %ld is multiply allocated\nInode list:\n",(long)zone);
  703.     for(p=fzlist;p;p=p->next)
  704.     {
  705.         if(p->zone!=zone)continue;
  706.         p->flag|=FOUND;
  707.         printf("Inode %d\n",p->inum);
  708.         printf("Mod time %s\n",ctime(&p->mod));
  709.         if(ask("Remove Zone?","Removed")) p->flag |=REMOVE;
  710.     }
  711. }
  712.  
  713. /* Return non-zero if 'zone' is a duplicate. If the FOUND flag is set for
  714.  * this zone ignore the request, as it means that this duplicate zone list
  715.  * is complete.
  716.  */
  717.  
  718. static int is_dup(zone)
  719. zone_nr zone;
  720. {
  721.     zlist *p;
  722.     for(p=fzlist;p;p=p->next)
  723.         if(p->zone==zone)
  724.         {
  725.             if(p->flag & FOUND) return 0;
  726.             return 1;
  727.         }
  728.     return 0;
  729. }
  730.  
  731. /* Returns non-zero if zone is marked for removing, if it is marked then
  732.  * remove the zone member from the duplicate list. If it isn't then set 
  733.  * the flag IGNORE so that subsequent is_rem()'s pass over it silently.
  734.  * If the zone is removed and no zones remain with this number, free its
  735.  * entry in the zone bitmap.
  736.  */
  737.  
  738. static int is_rem(zone)
  739. zone_nr zone;
  740. {
  741.     zlist *p,*q;
  742.     for(p=fzlist,q=0;p;p=p->next)
  743.     {
  744.         if( (p->zone==zone) && !(p->flag & IGNORE))
  745.         {
  746.             if(p->flag & REMOVE)
  747.             {
  748.                 if(!q) fzlist=p->next;
  749.                 else q->next=p->next;
  750.                 free(p);
  751.                 if(p==lzlist) lzlist=q;
  752.                 /* Last reference ? */
  753.                 for(p=fzlist;p && (p->zone!=zone);p=p->next) ;
  754.                 if(!p) unmark_zone(zone);
  755.                 return 1;
  756.             }
  757.             p->flag |= IGNORE;
  758.             return 0;
  759.         }
  760.         q=p;
  761.     }
  762.     return 0;
  763. }
  764.  
  765. /* check_root() test the root inode, determine directory increment if none
  766.  * specified.
  767.  */
  768.  
  769. static void check_root()
  770. {
  771.     dir_struct dir[DPB];
  772.     int i;
  773.     int oddroot;
  774.     read_inode_init();
  775.     cino=ROOT_INODE;
  776.     read_inode();
  777.     if((rip->i_mode & I_TYPE)!=I_DIRECTORY)
  778.     {
  779.         fprintf(stderr,"Root Inode Not a Directory\n");
  780.         if(!incr && ask("Check anyway?","Continuing...")) oddroot=1;
  781.         else
  782.         {
  783.           if(!incr)
  784.           {
  785.             fprintf(stderr,"Enter Increment Manually with '-d' option\n");
  786.             close_device();
  787.             exit(1);
  788.           }
  789.           if(!ask("Reallocate?","Reallocated"))
  790.           {
  791.             close_device();
  792.             exit(1);
  793.           }
  794.           badroot=1;
  795.           return;
  796.         }
  797.     }
  798.     else oddroot=0;
  799.  
  800.     if(incr) return;
  801.     if(!chk_range(rip->i_zone[0]))
  802.     {
  803.         fprintf(stderr,"Bad First Zone In Root Inode\n");
  804.         if(!ask("Assume Increment 1?","Assuming increment 1"))
  805.         {
  806.             close_device();
  807.             exit(1);
  808.         }
  809.         incr=1;
  810.         return;    
  811.     }
  812.  
  813.     read_zone(rip->i_zone[0],dir);
  814.  
  815.     if(strcmp(dir->d_name,"."))
  816.     {
  817.         fprintf(stderr,"No or bad '.' in Root Inode.\n");
  818.         fprintf(stderr,"Use the '-d' option to set increment.\n");
  819.         close_device();
  820.         exit(1);
  821.     }
  822.  
  823.     for(i=1;i<DPB;i++) if(!strcmp(dir[i].d_name,"..")) break;
  824.  
  825.     if(NPOW2(i) || (i > 8))
  826.     {
  827.         fprintf(stderr,"Can't Work Out Increment: Use the -d option\n");
  828.         close_device();
  829.         exit(1);
  830.     }
  831.  
  832.     incr=i;
  833.  
  834. #ifdef V1
  835.     /* Linux compatability */
  836.     if(incr==2 && Super->s_magic==SUPER_V1)
  837.     {
  838.         fprintf(stderr,
  839.             "Old Style Superblock for V1, increment 2 filesystem\n");
  840.         if(ask("Convert?","Converted"))
  841.         {
  842.             Super->s_magic=SUPER_V1_30;
  843.             write_zone(1,Super);
  844.         }
  845.     }
  846. #endif
  847.     if(oddroot)
  848.     {
  849.         fprintf(stderr,"Root Inode not directory but otherwise OK.\n");
  850.         if(!ask("Fix?","Fixed")) return;
  851.         rip->i_mode= I_DIRECTORY | 0777;
  852.         cdirty=1;
  853.         read_inode_init();
  854.     }
  855.  
  856.     return;
  857. }
  858.  
  859. /* traverse_dir(), send all the entries of a dir (with the entry number),
  860.  * to the function 'func'. If this returns non-zero then the entry was
  861.  * modified, BUG: Ignores double-indirection block, but anyone with a
  862.  * directory this big must be doing it to try and fool us (it means more
  863.  * than 33000 entries !).
  864.  */
  865.  
  866. static void traverse_dir(func)
  867. int (*func)();
  868. {
  869.     unsigned entry=0;
  870.     long nentries=rip->i_size/(DSIZE*incr),i;
  871.     zone_nr nzones=(nentries+DPB/incr-1)/(DPB/incr);
  872.     dir_struct dir[DPB];
  873.     zone_nr znr;
  874.     for(znr=0;znr < min(NDIR,nzones); znr++)
  875.     {
  876.         if(chk_range(rip->i_zone[znr]))
  877.         {
  878.             int zdirty=0;
  879.             read_zone(rip->i_zone[znr],dir);
  880.             for(i=0;(i<min(DPB/incr,nentries)) && !quit_trav;
  881.                                     i++,entry++)
  882.                 if((*func)(&dir[i*incr],entry)) zdirty=1;
  883.             if(zdirty) write_zone(rip->i_zone[znr],dir);
  884.             if(quit_trav) return;
  885.         }
  886.         else entry +=DPB/incr;
  887.         nentries-=DPB/incr;
  888.         if(nentries<=0) return;
  889.     }
  890.     nzones-=NDIR;
  891.     if(chk_range(rip->i_zone[NDIR]) )
  892.     {
  893.         zone_nr tmp[NINDIR];
  894.         read_zone(rip->i_zone[NDIR],tmp);
  895.         for(znr=0;znr<min(NINDIR,nzones);znr++)
  896.         {
  897.             if(chk_range(tmp[znr]))
  898.             {
  899.                 int zdirty=0;
  900.                 read_zone(tmp[znr],dir);
  901.                 for(i=0;(i<min(DPB/incr,nentries)) && !quit_trav;
  902.                                 i++,entry++)
  903.                     if( (*func)(&dir[i*incr],entry) )zdirty=1;
  904.                 if(zdirty) write_zone(tmp[znr],dir);
  905.                 if(quit_trav) return;
  906.             }
  907.             else entry +=DPB/incr;
  908.             nentries-=DPB/incr;
  909.             if(nentries<=0) return;
  910.         }
  911.     }
  912. }
  913.  
  914. /* Add an entry to a dir, this uses traverse_dir to see if there are any
  915.  * free slots, if not then add a zone.
  916.  */
  917.  
  918. static long lastentry;
  919. static dir_struct *add;
  920. static dir_struct newzone[DPB];
  921.  
  922. static int add_dirent(adir)
  923. dir_struct *adir;
  924. {
  925.     long tsize,zoneadd,addz;
  926.     tsize=rip->i_size;
  927.     /* Expand the dir by one entrylength, reset later if get empty slot */
  928.     rip->i_size+=DSIZE*incr;
  929.     rip->i_size &= ~(DSIZE*incr-1);
  930.     lastentry=rip->i_size/(DSIZE*incr)-1;
  931.     add=adir;
  932.     quit_trav=0;
  933.     traverse_dir(addfunc);
  934.     if(quit_trav)
  935.     {
  936.         /* If not last entry, restore size */
  937.         if(quit_trav==1) rip->i_size=tsize;
  938.         else cdirty=1;
  939.         quit_trav=0;
  940.         return 0;
  941.     }
  942.  
  943.     /* OK, need to add a zone, ignore any zone numbers already here,
  944.      * if there are any then they are bogus and should have been 
  945.      * removed in pass1.
  946.      */
  947.  
  948.     cdirty=1;
  949.     zoneadd=rip->i_size/BLOCKSIZE;
  950.  
  951.     if(!(addz=alloc_zone()))
  952.     {
  953.         printf("No free Zones\n");
  954.         return 1;
  955.     }
  956.     /* Room in direct zones ? */
  957.     if(zoneadd<NDIR) rip->i_zone[zoneadd]=addz;
  958.     else
  959.     /* Nope, need indirecton block */
  960.     {
  961.         zone_nr tmp[NINDIR];
  962.         zoneadd-=NDIR;
  963.         if(zoneadd >= NINDIR)
  964.         {
  965.             printf("Can't Expand Directory, Too Large\n");
  966.             clrbit(addz-minzone+1,szbitmap);
  967.             return 1;
  968.         }
  969.         if(!chk_range(rip->i_zone[NDIR]))
  970.         {
  971.             bzero((char *)tmp,BLOCKSIZE);
  972.             if( !(rip->i_zone[NDIR]=alloc_zone()) )        
  973.             {
  974.                 printf("No Free Zones\n");
  975.                 clrbit(addz-minzone+1,szbitmap);
  976.                 return 1;
  977.             }
  978.         }
  979.         else read_zone(rip->i_zone[NDIR],tmp);
  980.         tmp[zoneadd]=addz;
  981.         write_zone(rip->i_zone[NDIR],tmp);
  982.     }
  983.     cpdir(newzone,adir);
  984.  
  985.     write_zone(addz,newzone);
  986.     return 0;
  987. }
  988.  
  989. static int addfunc(dir,entry)
  990. dir_struct *dir;
  991. unsigned entry;
  992. {
  993.     if(entry<2) return 0;
  994.     /* If free , or last entry, overwrite */
  995.     if(!dir->d_inum || entry==lastentry)
  996.     {
  997.         cpdir(dir,add);
  998.         quit_trav=1;
  999.         if(entry==lastentry) quit_trav=2;
  1000.         return 1;
  1001.     }
  1002.     return 0;
  1003. }
  1004.  
  1005. static char *tname;
  1006. static unsigned ifind;
  1007.  
  1008. static void show_name(inl)
  1009. ilist *inl;
  1010. {
  1011.     inode_stat *itmp;
  1012.  
  1013.     char *tmpfnam;
  1014.  
  1015.     long pathlen;
  1016.  
  1017.     if(!(tname=malloc(incr*16-1)) ) fatal("Out of memory");
  1018.  
  1019.     /* Estimate maximum filename length of file
  1020.      * do this by counting how many directories we pass
  1021.      * through on way to root. Then assume all maximum
  1022.      * length.
  1023.      */
  1024.  
  1025.     for(pathlen=0,itmp=&inode_status[inl->iparent-1];;)
  1026.     {
  1027.         if(!(itmp->flag & I_FOUND)) break;
  1028.         pathlen++;
  1029.         if(itmp==inode_status) break;
  1030.         itmp=&inode_status[itmp->parent-1];
  1031.     }
  1032.  
  1033.     /* original link not counted so far and include \'s */
  1034.  
  1035.     pathlen = (pathlen+1)*incr*17-1;
  1036.  
  1037.     tmpfnam = malloc(pathlen);
  1038.  
  1039.     if(!tmpfnam) fatal("Out of Memory");
  1040.  
  1041.     strcpy(tmpfnam,inl->name);
  1042.     strrev(tmpfnam);
  1043.     strcat(tmpfnam,"\\");
  1044.  
  1045.     itmp=&inode_status[inl->iparent-1];
  1046.     ifind=inl->iparent;
  1047.  
  1048.     while(ifind!=ROOT_INODE)
  1049.     {
  1050.         if(itmp->flag & I_FOUND)
  1051.         {
  1052.             lookup_name(itmp);
  1053.             if(!*tname)
  1054.             {
  1055.                 fprintf(stderr,
  1056.                     "Can't find name of inode %d\n",inl->inum);
  1057.                 return;
  1058.             }
  1059.             strrev(tname);
  1060.             strcat(tmpfnam,tname);
  1061.             strcat(tmpfnam,"\\");
  1062.         }
  1063.         else
  1064.         {
  1065.             strcat(tmpfnam,"(nahpro)");
  1066.             /* "orphan" backwards, geddit? */
  1067.             break;
  1068.         }        
  1069.         ifind=itmp->parent;
  1070.         itmp=&inode_status[itmp->parent-1];
  1071.         
  1072.     }
  1073.  
  1074.     strrev(tmpfnam);
  1075.     fprintf(stderr,"Inode %5d Filename: %s\n",inl->inum,tmpfnam);
  1076.  
  1077.     free(tname);
  1078.     free(tmpfnam);
  1079. }
  1080.  
  1081. static void lookup_name(in)
  1082. inode_stat *in;
  1083. {
  1084.     cino=in->parent;
  1085.     tname[0]=0;
  1086.     read_inode();
  1087.     traverse_dir(i_to_name);
  1088.     quit_trav=0;
  1089. }    
  1090.  
  1091. static int i_to_name(dir,entry)
  1092. dir_struct *dir;
  1093. unsigned entry;
  1094. {
  1095.     if(entry < 2 ) return 0;    /* Ignore dots */
  1096.     if(dir->d_inum==ifind) 
  1097.     {
  1098.         strncpy(tname,dir->d_name,incr*16-2);
  1099.         tname[incr*16-2]=0;
  1100.         quit_trav=1;
  1101.     }
  1102.     return 0;
  1103. }
  1104.  
  1105. /* Make a 'lost+found' directory if none exists */
  1106.  
  1107. static int mklost()
  1108. {
  1109.     unsigned tino;
  1110.     unsigned ctemp;
  1111.     zone_nr tzone;
  1112.     int i;
  1113.     dir_struct dir[DPB];
  1114.     printf("No lost+found directory\n");
  1115.     if(!ask("Create?","Created")) return 0;
  1116.     tino=alloc_inode();
  1117.     if(!tino) return 0;
  1118.     if(!(tzone=alloc_zone())) return 0;
  1119.     ctemp=cino;
  1120.     cino=tino;
  1121.     read_inode();
  1122.     for(i=1;i<NR_ZONE;i++) rip->i_zone[i]=0;
  1123.     rip->i_zone[0]=tzone;
  1124.     rip->i_mode=I_DIRECTORY | 0755;
  1125.     rip->i_mtime=time(NULL);
  1126.     rip->i_uid=0;
  1127.     rip->i_gid=0;
  1128.     rip->i_size=DSIZE*2*incr;
  1129.     rip->i_nlinks=2;
  1130.     cdirty=1;
  1131.     strcpy(dir[0].d_name,".");
  1132.     dir[0].d_inum=tino;
  1133.     strcpy(dir[incr].d_name,"..");
  1134.     dir[incr].d_inum=ROOT_INODE;
  1135.     write_zone(tzone,dir);
  1136.  
  1137.     strcpy(dir[0].d_name,lfname);
  1138.     dir[0].d_inum=tino;
  1139.  
  1140.     cino=ROOT_INODE;
  1141.     read_inode();
  1142.     rip->i_nlinks++;
  1143.     cdirty=1;
  1144.  
  1145.     add_dirent(dir);
  1146.  
  1147.     cino=ctemp;
  1148.     lfinode=tino;
  1149.  
  1150.     inode_status[tino-1].flag = I_DIR|I_D|I_DD|I_FOUND;
  1151.     inode_status[tino-1].links=0;
  1152.     inode_status[tino-1].parent=ROOT_INODE;
  1153.  
  1154.     return 1;
  1155. }
  1156.  
  1157. /* Simple enoungh this one : check '.' and '..' are present, check '.' points
  1158.  * to this directory, note the value of '..' . Make elementary fixes as well.
  1159.  */
  1160.  
  1161. static void check_dots()
  1162. {
  1163.     dir_struct dir[DPB];
  1164.     int dirty=0;
  1165.     if(chk_range(rip->i_zone[0]))
  1166.     {
  1167.         read_zone(rip->i_zone[0],dir);
  1168.         if(strcmp(dir->d_name,"."))
  1169.         {
  1170.             printf("No '.' in directory inode %ld\n",cino);
  1171.             if(ask("Fix?","Fixed"))
  1172.             {
  1173.             /* If this entry is occupied, add an identical entry
  1174.              * to the dir, because this one will be overwritten.
  1175.              */
  1176.             if(chk_irange(dir->d_inum)) add_dirent(dir);
  1177.  
  1178.             strcpy(dir[0].d_name,".");
  1179.             dir->d_inum=cino;
  1180.             dirty=1;
  1181.             ist->flag|=I_D;
  1182.             }
  1183.         }
  1184.         else ist->flag|=I_D;
  1185.  
  1186.         if(dir->d_inum!=cino)
  1187.         {
  1188.             printf("Bad '.' Entry in directory inode %ld\n",cino);
  1189.             if(ask("Fix?","Fixed"))
  1190.             {
  1191.                 dir->d_inum=cino;
  1192.                 dirty=1;
  1193.             }
  1194.         }
  1195.  
  1196.         if(strcmp(dir[incr].d_name,".."))
  1197.         {
  1198.             printf("Missing '..' in directory inode %ld",cino);
  1199.             if(ask("Fix?","Fixed"))
  1200.             {
  1201.                 if(chk_irange(dir[incr].d_inum)) 
  1202.                             add_dirent(&dir[incr]);
  1203.  
  1204.                 strcpy(dir[incr].d_name,"..");
  1205.                 dir[incr].d_inum=0;    /* Can't fix this yet */
  1206.                 ist->flag|=I_FDD;
  1207.                 ist->flag|=I_DD;
  1208.                 dirty=1;
  1209.             }
  1210.         }
  1211.         else
  1212.         {
  1213.             ist->parent=dir[incr].d_inum;
  1214.             ist->flag|=I_DD;
  1215.         }
  1216.         if(dirty) write_zone(rip->i_zone[0],dir);
  1217.     }
  1218. }
  1219.  
  1220. /* Check inode numbers against list after checking _pass2 wont kill the entry */
  1221.  
  1222. static int pass2(dir,entry)
  1223. dir_struct *dir;
  1224. unsigned entry;
  1225. {
  1226.     int ret;
  1227.     ret=_pass2(dir,entry);
  1228.  
  1229.     if(!ret)
  1230.     {
  1231.         llist *p;
  1232.         for(p=inums;p;p=p->next) if(dir->d_inum==p->member) break;
  1233.         if(p)
  1234.         {
  1235.             ilist *nxt;
  1236.             nxt=malloc(sizeof(ilist)+incr*16);
  1237.             if(!nxt) fatal("Out of memory");
  1238.             strncpy(nxt->name,dir->d_name,incr*16-2);
  1239.             nxt->name[incr*16-2]=0;
  1240.             nxt->inum=dir->d_inum;
  1241.             nxt->iparent=cino;
  1242.             nxt->next=inolist;
  1243.             inolist=nxt;
  1244.         }
  1245.     }
  1246.  
  1247.     return ret;
  1248. }
  1249.  
  1250. /* OK this is the nasty bit. At this point we know the value of '..' in a
  1251.  * directory (if present). Check all directory entries and offer fixes, also
  1252.  * mark each inode as it is 'found' and update link counts.
  1253.  */
  1254.  
  1255. static int _pass2(dir,entry)
  1256. dir_struct *dir;
  1257. unsigned entry;
  1258. {
  1259.     inode_stat *iarr;
  1260.  
  1261.     if(!dir->d_inum) return 0;
  1262.  
  1263.     if(!chk_irange(dir->d_inum))
  1264.     {
  1265.         inerr("Ilegal Inode Number\n");
  1266.         if(ask("Delete?","Deleted"))
  1267.         {
  1268.             dir->d_inum=0;
  1269.             return 1;
  1270.         }
  1271.         return 0;    /* Can't do anything else with it */
  1272.     }
  1273.  
  1274.     if( (cino==ROOT_INODE) && !strcmp(dir->d_name,lfname))lfinode=dir->d_inum;
  1275.  
  1276.     iarr=&inode_status[dir->d_inum-1];
  1277.     iarr->links--;
  1278.  
  1279.     if(badname(dir->d_name))
  1280.     {
  1281.         printf("Bad Name %.*s in Directory Inode %ld\n",
  1282.                     MMAX_FNAME(incr),dir->d_name,cino);
  1283.         if(ask("Delete?","Deleted"))
  1284.         {
  1285.             dir->d_inum=0;
  1286.             iarr->links++;
  1287.             return 1;
  1288.         }
  1289.     }
  1290.  
  1291.     if(entry && (!strcmp(dir->d_name,".")))
  1292.     {
  1293.         inerr("Extra '.' entry");
  1294.         if(ask("Delete?","Deleted"))
  1295.         {
  1296.             dir->d_inum=0;
  1297.             iarr->links++;
  1298.             return 1;
  1299.         }
  1300.         return 0;
  1301.     }
  1302.  
  1303.     if( (entry!=1) && !strcmp(dir->d_name,"..") )
  1304.     {
  1305.         inerr("Extra '..' entry");
  1306.         if(ask("Delete?","Deleted"))
  1307.         {
  1308.             dir->d_inum=0;
  1309.             iarr->links++;
  1310.             return 1;
  1311.         }
  1312.         return 0;
  1313.     }
  1314.  
  1315.     if( ( (entry==0) && (ist->flag & I_D) )
  1316.                 || ( (entry==1) && (ist->flag & I_DD ) ) )
  1317.             return 0;
  1318.  
  1319.     if(iarr->flag & I_FREE)
  1320.     {
  1321.         inerr("Bad Link To Free Inode");
  1322.         if(ask("Delete?","Deleted"))
  1323.         {
  1324.             dir->d_inum=0;
  1325.             iarr->links++;
  1326.             return 1;
  1327.         }
  1328.         return 0;
  1329.     }
  1330.  
  1331.     /* Tricky bit : link to directory. For this pass only recognise as
  1332.      * 'found' if the link is present in the correct parent directory.
  1333.      * If this isn't the case either '..' is wrong or this is an illegal
  1334.      * hard link, this is resolved on the next pass.
  1335.      * If it isn't a directory then mark found, as multiple links are OK.
  1336.      */
  1337.     if(iarr->flag & I_DIR)
  1338.     {
  1339.         if (iarr->parent==cino)
  1340.         {
  1341.     /* If the 'FOUND' flag is set then multiple links in this dir */
  1342.             if(iarr->flag & I_FOUND)
  1343.             {
  1344.                 inerr("Illegal Hard Link To Directory");
  1345.                 if(ask("Remove","Removed"))
  1346.                 {
  1347.                     dir->d_inum=0;
  1348.                     iarr->links++;
  1349.                     return 1;
  1350.                 }
  1351.             }
  1352.             else iarr->flag |= I_FOUND;
  1353.         }
  1354.         else ist->flag |= I_LINK;
  1355.     }
  1356.     else iarr->flag |= I_FOUND;
  1357.  
  1358.     return 0;
  1359. }
  1360.  
  1361. /* At this point all directories which have a link in '..' have the flag
  1362.  * I_FOUND. So if a hard link to a directory is found then it is one of:
  1363.  * 1. An erroneous hard link (if it isn't in the parent and I_FOUND set).
  1364.  * 2. A proper link but the value of '..' is wrong in the linked dir.
  1365.  * If '..' is wrong and two hard links are found then the first is taken to
  1366.  * be valid, there isn't any real way to find out the genuine link in this
  1367.  * case.
  1368.  */
  1369.  
  1370. static int pass2a(dir,entry)
  1371. dir_struct *dir;
  1372. unsigned entry;
  1373. {
  1374.     inode_stat *iarr;
  1375.     /* Ignore dot's and invalid links */
  1376.     if( (!entry && (ist->flag & I_D) )||
  1377.         (entry==1 && (ist->flag & I_DD) ) ||
  1378.         !chk_irange(dir->d_inum) ) return 0;    
  1379.     iarr=&inode_status[dir->d_inum-1];
  1380.     /* If not dir , ignore */
  1381.  
  1382.     if(! (iarr->flag & I_DIR) ) return 0;
  1383.  
  1384.     /* Is this the parent ? */
  1385.     if(iarr->parent==cino) return 0;
  1386.  
  1387.     /* Does parent have a valid link ? */
  1388.     if(iarr->flag & I_FOUND)
  1389.     {
  1390.         printf("Bad Hard Link to Directory in Inode %ld\n",cino);
  1391.         if(ask("Remove?","Removed"))
  1392.         {
  1393.             dir->d_inum=0;
  1394.             iarr->links++;
  1395.             return 1;
  1396.         }
  1397.         return 0;
  1398.     }
  1399.  
  1400.     /* Hmm '..' parent has no link, must be invalid '..' */
  1401.  
  1402.     iarr->flag|=I_FOUND;
  1403.     iarr->flag|=I_FIXDD;
  1404.     iarr->parent=cino;
  1405.     return 0;
  1406. }
  1407.  
  1408. /* Almost there: fix any directories '..' entries if there is an
  1409.  * error found, if the I_FDD flag is set, do the changes silently.
  1410.  */
  1411.  
  1412. static void fix_dots()
  1413. {
  1414.     dir_struct dir[DPB];
  1415.     if(!(ist->flag & I_FDD)) 
  1416.     {
  1417.         inerr("Bad '..' entry");
  1418.         if(!ask("Fix?","Fixed")) return;
  1419.     }
  1420.     read_zone(rip->i_zone[0],dir);
  1421.     if(chk_irange(dir[incr].d_inum))
  1422.                 inode_status[dir[incr].d_inum-1].links++;
  1423.     dir[incr].d_inum=ist->parent;
  1424.     inode_status[ist->parent-1].links--;
  1425.     write_zone(rip->i_zone[0],dir);
  1426. }
  1427.  
  1428. /* Inode readers : there are two of these. next_inode() is used in the
  1429.  * initial stages where all inodes have to be read twice, it uses a big
  1430.  * buffer for this purpose, if the 'cdirty' flag is set then it writes out
  1431.  * the buffer first.
  1432.  */
  1433.  
  1434. static d_inode *ncache_start,*ncache_end,*ncache;
  1435. static long ncache_blk;
  1436.  
  1437. /* Initialise and flush big cache */
  1438. static void next_init()
  1439. {
  1440.     if(!ncache_start)
  1441.     {
  1442.         ncache_start=malloc(NSIZE*BLOCKSIZE);
  1443.         if(!ncache_start)fatal("No memory for inode cache");
  1444.         ncache_end=ncache_start+NSIZE*IPB;
  1445.     }
  1446.     if(cdirty) write_blocks(ncache_blk,NSIZE,ncache_start);
  1447.     cdirty=0;
  1448.     ncache=ncache_start;
  1449.     ncache_blk=0;
  1450. }
  1451.  
  1452. static void next_inode()
  1453. {
  1454.     if(ncache_blk==0)
  1455.     {
  1456.         read_blocks(ioff,NSIZE,ncache_start);
  1457.         ncache_blk=ioff;
  1458.     }
  1459.     if(ncache!=ncache_end)
  1460.     {
  1461.         rip=ncache;
  1462.         ncache++;
  1463.         return;
  1464.     }
  1465.     if(cdirty)
  1466.     {
  1467.         cdirty=0;
  1468.         write_blocks(ncache_blk,NSIZE,ncache_start);
  1469.     }
  1470.     ncache_blk+=NSIZE;
  1471.     read_blocks(ncache_blk,NSIZE,ncache_start);
  1472.     ncache=ncache_start;
  1473.     rip=ncache;
  1474.     ncache++;
  1475.     return;
  1476. }
  1477.  
  1478. static d_inode ltmp[IPB];
  1479.  
  1480. static void read_inode_init()
  1481. {
  1482.     if(cdirty)
  1483.     {
  1484.         write_blocks(ncache_blk,1,ltmp);
  1485.         cdirty=0;
  1486.     }
  1487.     ncache_blk=0;
  1488. }
  1489.  
  1490. static void read_inode()
  1491. {
  1492.     zone_nr blk=ioff+(cino-1)/IPB  ;
  1493.     if(!cino || (cino>maxino) )fatal("Internal error: inode out of range");
  1494.     if(ncache_blk!=blk)
  1495.     {
  1496.         if(cdirty)
  1497.         {
  1498.             cdirty=0;
  1499.             write_blocks(ncache_blk,1,ltmp);
  1500.         }
  1501.         ncache_blk=blk;
  1502.         read_blocks(ncache_blk,1,ltmp);
  1503.     }
  1504.     rip=<mp[(cino-1)%IPB];
  1505. }
  1506.  
  1507. static long alloc_inode()
  1508. {
  1509.     long ret;
  1510.     inode_stat *istmp=inode_status;
  1511.     for(ret=0;ret<maxino;ret++,istmp++)if(istmp->flag &I_FREE) return ret+1;
  1512.     return 0;
  1513. }
  1514.  
  1515. /* Reallocate root inode. Here the root inode is set up as a dir with '.','..'
  1516.  * and 'lost+found'. The connectivity algorithm should then be able to reconnect
  1517.  * all the orphaned inodes. Note: at this point the inode structures should at
  1518.  * least be set up, and the shadow zone bitmap, so we can safely allocate new
  1519.  * zones/inodes.
  1520.  */
  1521.  
  1522. static void fix_root()
  1523. {
  1524.     long z1,z2;
  1525.     time_t now;
  1526.  
  1527.     dir_struct rdir[DPB];
  1528.  
  1529.     cino=ROOT_INODE;
  1530.     /* First things first : allocate 2 zones */
  1531.     z1=alloc_zone();
  1532.  
  1533.     z2=alloc_zone();
  1534.  
  1535.     if(!z1 || !z2) 
  1536.         fatal("No Free Zones To Reallocate Root Inode");
  1537.  
  1538.     lfinode=alloc_inode();
  1539.  
  1540.     if(!lfinode)
  1541.         fatal("No Free Inodes To Reallocate 'lost+found'");
  1542.  
  1543.     /* Setup inode status flags */
  1544.     inode_status->flag= I_DIR | I_FOUND;
  1545.     inode_status->links=3;
  1546.     inode_status[lfinode-1].flag= I_DIR;
  1547.     inode_status[lfinode-1].links=2;
  1548.  
  1549.     read_inode_init();
  1550.     read_inode();
  1551.  
  1552.     now=time((time_t *)NULL);
  1553.  
  1554.     *rip=zinode;
  1555.  
  1556.     /* Setup root inode */
  1557.     rip->i_size= DSIZE*incr*3;        /* 3 entries */
  1558.     rip->i_mode= I_DIRECTORY | 0777;    /* Dir + 777 mode */
  1559.     rip->i_zone[0]=z1;            /* 1 Zone */
  1560.     rip->i_mtime=now;
  1561.     rip->i_nlinks=3;
  1562. #ifdef V2
  1563.     rip->i_atime=now;
  1564.     rip->i_ctime=now;
  1565. #endif
  1566.  
  1567.     /* Root Directory */
  1568.     bzero(rdir,BLOCKSIZE);
  1569.             
  1570.     strcpy(rdir[0].d_name,".");
  1571.     rdir[0].d_inum=ROOT_INODE;
  1572.     strcpy(rdir[incr].d_name,"..");
  1573.     rdir[incr].d_inum=ROOT_INODE;
  1574.     strcpy(rdir[incr*2].d_name,lfname);
  1575.     rdir[incr*2].d_inum=lfinode;
  1576.  
  1577.     write_zone(z1,rdir);
  1578.     cdirty=1;
  1579.  
  1580.     cino=lfinode;
  1581.     read_inode();
  1582.  
  1583.     /* Setup 'lost+found' inode */
  1584.     
  1585.     *rip=zinode;
  1586.  
  1587.     rip->i_size=DSIZE*incr*2;
  1588.     rip->i_mode=I_DIRECTORY | 0777;
  1589.     rip->i_zone[0]=z2;
  1590.     rip->i_mtime=now;
  1591.     rip->i_nlinks=2;
  1592. #ifdef V2
  1593.     rip->i_atime=now;
  1594.     rip->i_ctime=now;
  1595. #endif
  1596.  
  1597.     /* l+f dir same as root except for '.' */
  1598.     rdir[0].d_inum=lfinode;
  1599.  
  1600.     write_zone(z2,rdir);
  1601.     cdirty=1;
  1602.  
  1603.     read_inode_init();
  1604. }
  1605.